//
//  UITableView+PPKit.swift
//  PPKit
//
//  Created by xiaopin on 16/8/31.
//  Copyright © 2016年 pinguo. All rights reserved.
//  https://gitee.com/xiaopindev/PPKit
//  https://github.com/xiaopindev
//  https://xiaopin.cnblogs.com

import UIKit

public extension UITableView {
    
    /// 注册手写方式的cell类对象
    ///
    /// - Parameters:
    ///   - cellClass: <#cellClass description#>
    ///   - reuseID: <#reuseID description#>
    func registerCellClass(_ cellClass: AnyClass, reuseID:String) {
        self.register(cellClass, forCellReuseIdentifier: reuseID)
    }
    
    /// 注册Xib
    ///
    /// - Parameter cellName: 重用ID，值和Cell的文件名一致
    func registerCellNib(_ cellName:String) {
        let nib = UINib(nibName: cellName, bundle: nil)
        self.register(nib, forCellReuseIdentifier: cellName)
    }
    
    func registerHeaderFooterViewClass(_ viewClass: AnyClass) {
        let identifier = String.className(viewClass)
        self.register(viewClass, forHeaderFooterViewReuseIdentifier: identifier)
    }
    
    func registerHeaderFooterViewNib(_ viewClass: AnyClass) {
        let identifier = String.className(viewClass)
        let nib = UINib(nibName: identifier, bundle: nil)
        self.register(nib, forHeaderFooterViewReuseIdentifier: identifier)
    }

    /// 空数据显示提示
    ///
    /// - Parameter rowCount: 显示时0，不显示1
    func noData(_ rowCount: Int? = 0, text:String = "MT_NoData".localized) {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)
            
            let imgView = UIImageView()
            imgView.frame = CGRect(x: 0, y: 80, width: 262, height: 105)
            imgView.image = UIImage(named: "mt_nodata")
            imgView.center = CGPoint(x: bgView.center.x, y: 130)
            bgView.addSubview(imgView)
            
            let label = UILabel(frame: pp_frame(0, imgView.top + imgView.height + 15, self.bounds.size.width, 20))
            label.text = text
            label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
            label.font = .systemFont(ofSize: 14)
            label.textAlignment = .center
            bgView.addSubview(label)
            
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
    
    /// 空数据显示提示2
    ///
    /// - Parameter rowCount: 显示时0，不显示1
    func noData2(_ rowCount: Int? = 0, text:String = "暂无数据~" , imageNameStr:String = "mt_nodata") {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)
            
            let imgView = UIImageView()
            imgView.frame = CGRect(x: 0, y:80, width: 66, height: 66)
            imgView.image = UIImage(named: imageNameStr)
            imgView.center = CGPoint(x: bgView.center.x, y: 240)
            bgView.addSubview(imgView)
            
            let label = UILabel(frame: pp_frame(0, imgView.top + imgView.height + 25, self.bounds.size.width, 20))
            label.text = text
            label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
            label.font = UIFont.systemFont(ofSize: 15, weight: .bold)
            label.textAlignment = .center
            bgView.addSubview(label)
            
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
    /// 空数据显示提示3
    ///
    /// - Parameter rowCount: 显示时0，不显示1
    func noData3(_ rowCount: Int? = 0, text:String = "暂无数据~" , imageNameStr:String = "mt_nodata") {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)
            
            let imgView = UIImageView()
            imgView.frame = CGRect(x: 0, y:80, width: 66, height: 66)
            imgView.image = UIImage(named: imageNameStr)
            imgView.center = CGPoint(x: bgView.center.x, y: 240)
            bgView.addSubview(imgView)
            
            let label = UILabel(frame: pp_frame(0, imgView.top + imgView.height + 25, self.bounds.size.width, 20))
            label.text = text
            label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
            label.font = UIFont.systemFont(ofSize: 15, weight: .bold)
            label.textAlignment = .center
            bgView.addSubview(label)
            
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
    
    /**
     空收藏显示提示
     
     :param: rowCount 显示时0，不显示1
     */
    func noFavorites(_ rowCount: Int) {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)
            
            let imgView = UIImageView()
            imgView.frame = CGRect(x: 0, y: 80, width: 130, height: 82)
            imgView.image = UIImage(named: "mt_nodata")
            imgView.center = CGPoint(x: bgView.center.x, y: 130)
            bgView.addSubview(imgView)
            
            let label = UILabel(frame: pp_frame(0, imgView.top + imgView.height + 15, self.bounds.size.width, 20))
            label.text = "MT_NoFavorites".localized
            label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
            label.font = .systemFont(ofSize: 14)
            label.textAlignment = .center
            bgView.addSubview(label)
            
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
    
    func noFavoritesMy(_ rowCount: Int, text:String = "No favorites", subText:String = "Go to favorites", buttonText:String = "Reload") {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)

            let imgView = UIImageView.init(name: "collectionNodata")
            let titleLabel = UILabel.init(text: text, textColor: pp_color(.C222222), fontSize: 18.scale, weight: .bold, align: .center)
            let textLabel = UILabel.init(text: subText, textColor: pp_color(.C999999), fontSize: 12.scale, weight: .regular, align: .center, lines: 0,breakMode: .byWordWrapping)
            textLabel.setTextAndLineSpacing(text: subText, lineSpacing: 10.scale)
            let button = UIButton.init(text: buttonText, textColor: .white, bgColor: pp_color(.C159F48), font: .systemFont(ofSize: 15.scale, weight: .bold))
            button.tag = 1001
            imgView.beAddInto(bgView).snp.makeConstraints { m in
                m.width.equalTo(214.scale)
                m.height.equalTo(112.scale)
                m.top.equalTo(120.scale)
                m.centerX.equalToSuperview()
            }
            titleLabel.beAddInto(bgView).snp.makeConstraints { m in
                m.top.equalTo(imgView.snp.bottom).offset(5.scale)
                m.centerX.equalToSuperview()
            }
            textLabel.beAddInto(bgView).snp.makeConstraints { m in
                m.top.equalTo(titleLabel.snp.bottom).offset(8.scale)
                m.left.equalTo(40.scale)
                m.right.equalTo(-40.scale)
                m.centerX.equalToSuperview()
            }
            button.cornerRadius = 3
            button.beAddInto(bgView).snp.makeConstraints { m in
                m.top.equalTo(textLabel.snp.bottom).offset(25.scale)
                m.width.equalTo(138.scale)
                m.height.equalTo(40.scale)
                m.centerX.equalToSuperview()
            }
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
    
    func noResult(_ rowCount: Int = 0, text:String = "MT_NoSearchResult".localized) {
        if rowCount == 0 {
            let bgView = UIView(frame: self.bounds)
            
            let imgView = UIImageView()
            imgView.frame = CGRect(x: 0, y: 80, width: 130, height: 82)
            imgView.image = UIImage(named: "mt_nodata")
            imgView.center = CGPoint(x: bgView.center.x, y: 130)
            bgView.addSubview(imgView)
            
            let label = UILabel(frame: pp_frame(0, imgView.top + imgView.height + 15, self.bounds.size.width, 20))
            label.text = text
            label.textColor = #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1)
            label.font = .systemFont(ofSize: 14)
            label.textAlignment = .center
            bgView.addSubview(label)
            
            backgroundView = bgView
            separatorStyle = .none
        } else {
            backgroundView = nil
            separatorStyle = .none
        }
    }
}

extension UITableViewCell:GGReuseIdProtocol {}
extension UITableViewHeaderFooterView:GGReuseIdProtocol {}

extension GGReuseIdProtocol {
    static func reuseId() -> String {
        let id = "\(type(of:self))" as NSString
        let reuseId = id.substring(to:id.length-5)
        return reuseId
    }
}

protocol GGReuseIdProtocol {
    static func reuseId() -> String
}

extension UITableView {
    func deqCell<T:GGReuseIdProtocol>(c:T.Type) -> T? {//（备忘）
        return self.dequeueReusableCell(withIdentifier:c.reuseId()) as? T
    }
    
    func deqHeader<T:GGReuseIdProtocol>(h:T.Type) -> T? {
        return self.dequeueReusableHeaderFooterView(withIdentifier:h.reuseId()) as? T
    }
}


extension UITableView {
    func reloadData(_ completion: @escaping ()->()) {
        UIView.animate(withDuration: 0, animations: {
            self.reloadData()
        }, completion:{ _ in
            completion()
        })
    }
    
    func insertRowsAtBottom(_ rows: [IndexPath]) {
        //保证 insert row 不闪屏
        UIView.setAnimationsEnabled(false)
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        self.beginUpdates()
        self.insertRows(at: rows, with: .none)
        self.endUpdates()
        self.scrollToRow(at: rows[0], at: .bottom, animated: false)
        CATransaction.commit()
        UIView.setAnimationsEnabled(true)
    }
    
    func totalRows() -> Int {
        var i = 0
        var rowCount = 0
        while i < self.numberOfSections {
            rowCount += self.numberOfRows(inSection: i)
            i += 1
        }
        return rowCount
    }
    
    var lastIndexPath: IndexPath? {
        if (self.totalRows()-1) > 0{
            return IndexPath(row: self.totalRows()-1, section: 0)
        } else {
            return nil
        }
    }
    
    //插入数据后调用
    func scrollBottomWithoutFlashing() {
        guard let indexPath = self.lastIndexPath else {
            return
        }
        UIView.setAnimationsEnabled(false)
        CATransaction.begin()
        CATransaction.setDisableActions(true)
        self.scrollToRow(at: indexPath, at: .bottom, animated: false)
        CATransaction.commit()
        UIView.setAnimationsEnabled(true)
    }
    
    //键盘动画结束后调用
    func scrollBottomToLastRow(animated:Bool = false) {
        guard let indexPath = self.lastIndexPath else {
            return
        }
        self.scrollToRow(at: indexPath, at: .bottom, animated: animated)
    }
    
    func scrollBottomToLastRowWithAnimated() {
        guard let indexPath = self.lastIndexPath else {
            return
        }
        self.scrollToRow(at: indexPath, at: .top, animated:true)
    }
    
    func scrollToBottom(animated: Bool) {
        if self.canScrollToBottom && !self.isAtBottom {
            let bottomOffset = CGPoint(x: 0.0, y: self.contentSize.height - self.bounds.size.height)
            self.setContentOffset(bottomOffset, animated: animated)
        }
    }
    
    var isContentInsetBottomZero: Bool {
        get { return self.contentInset.bottom == 0 }
    }
    
    func resetContentInsetAndScrollIndicatorInsets() {
        self.contentInset = UIEdgeInsets.zero
        self.scrollIndicatorInsets = UIEdgeInsets.zero
    }
}

extension UIScrollView {
    fileprivate struct AssociatedKeys {
        static var kKeyScrollViewVerticalIndicator = "_verticalScrollIndicator"
        static var kKeyScrollViewHorizontalIndicator = "_horizontalScrollIndicator"
    }
    
    ///  YES if the scrollView's offset is at the very top.
    public var isAtTop: Bool {
        get { return self.contentOffset.y == 0.0 ? true : false }
    }
    
    ///  YES if the scrollView's offset is at the very bottom.
    public var isAtBottom: Bool {
        get {
            let bottomOffset = self.contentSize.height - self.bounds.size.height
            return self.contentOffset.y == bottomOffset ? true : false
        }
    }
    
    ///  YES if the scrollView can scroll from it's current offset position to the bottom.
    public var canScrollToBottom: Bool {
        get { return self.contentSize.height > self.bounds.size.height ? true : false }
    }
    
    /// The vertical scroll indicator view.
    public var verticalScroller: UIView {
        get {
            if (objc_getAssociatedObject(self, #function) == nil) {
                objc_setAssociatedObject(self, #function, self.safeValueForKey(AssociatedKeys.kKeyScrollViewVerticalIndicator), objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN);
            }
            return objc_getAssociatedObject(self, #function) as! UIView
        }
    }

    /// The horizontal scroll indicator view.
    public var horizontalScroller: UIView {
        get {
            if (objc_getAssociatedObject(self, #function) == nil) {
                objc_setAssociatedObject(self, #function, self.safeValueForKey(AssociatedKeys.kKeyScrollViewHorizontalIndicator), objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN);
            }
            return objc_getAssociatedObject(self, #function) as! UIView
        }
    }
    
    fileprivate func safeValueForKey(_ key: String) -> AnyObject{
        let instanceVariable: Ivar = class_getInstanceVariable(type(of: self), key.cString(using: String.Encoding.utf8)!)!
        return object_getIvar(self, instanceVariable) as AnyObject;
    }
    

     /**
     Sets the content offset to the top.
     
     - parameter animated: animated YES to animate the transition at a constant velocity to the new offset, NO to make the transition immediate.
     */
    public func scrollToTopAnimated(_ animated: Bool) {
        if !self.isAtTop {
            let bottomOffset = CGPoint.zero;
            self.setContentOffset(bottomOffset, animated: animated)
        }
    }

    /**
     Sets the content offset to the bottom.
     
     - parameter animated: animated YES to animate the transition at a constant velocity to the new offset, NO to make the transition immediate.
     */
    public func scrollToBottomAnimated(_ animated: Bool) {
        if self.canScrollToBottom && !self.isAtBottom {
            let bottomOffset = CGPoint(x: 0.0, y: self.contentSize.height - self.bounds.size.height)
            self.setContentOffset(bottomOffset, animated: animated)
        }
    }

    /**
      Stops scrolling, if it was scrolling.
     */
    public func stopScrolling() {
        guard self.isDragging else {
            return
        }
        var offset = self.contentOffset
        offset.y -= 1.0
        self.setContentOffset(offset, animated: false)

        offset.y += 1.0
        self.setContentOffset(offset, animated: false)
    }
}
